<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>JVM学习 | 辉辉的学习基地</title>
    <meta name="generator" content="VuePress 1.7.1">
    <link rel="icon" href="/blog/favicon.ico">
    <meta name="description" content="辉辉的学习基地是辉辉的个人博客，用于记录学习笔记、分享音乐、书籍、旅行等个人兴趣的站点。">
    <meta name="keywords" content="辉辉,辉辉的博客,博客,个人博客,vue,vuejs,vuepress,vuepress-theme-reco">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    
    <link rel="preload" href="/blog/assets/css/0.styles.bbb0eee4.css" as="style"><link rel="preload" href="/blog/assets/js/app.4c41a59b.js" as="script"><link rel="preload" href="/blog/assets/js/2.a039f8e7.js" as="script"><link rel="preload" href="/blog/assets/js/23.da1cba87.js" as="script"><link rel="preload" href="/blog/assets/js/4.bae9b8d2.js" as="script"><link rel="prefetch" href="/blog/assets/js/10.969d578d.js"><link rel="prefetch" href="/blog/assets/js/11.f93921d3.js"><link rel="prefetch" href="/blog/assets/js/12.a794f274.js"><link rel="prefetch" href="/blog/assets/js/13.d33e075d.js"><link rel="prefetch" href="/blog/assets/js/14.4da4367b.js"><link rel="prefetch" href="/blog/assets/js/15.bd9bf192.js"><link rel="prefetch" href="/blog/assets/js/16.318edc0e.js"><link rel="prefetch" href="/blog/assets/js/17.ebff9194.js"><link rel="prefetch" href="/blog/assets/js/18.17c4bd0a.js"><link rel="prefetch" href="/blog/assets/js/19.3a3638ec.js"><link rel="prefetch" href="/blog/assets/js/20.a1758358.js"><link rel="prefetch" href="/blog/assets/js/21.e2937215.js"><link rel="prefetch" href="/blog/assets/js/22.044317b3.js"><link rel="prefetch" href="/blog/assets/js/24.8906d05f.js"><link rel="prefetch" href="/blog/assets/js/25.8c51032b.js"><link rel="prefetch" href="/blog/assets/js/26.37e22ab7.js"><link rel="prefetch" href="/blog/assets/js/27.a9db888c.js"><link rel="prefetch" href="/blog/assets/js/28.d5f797ba.js"><link rel="prefetch" href="/blog/assets/js/29.b316a480.js"><link rel="prefetch" href="/blog/assets/js/3.a38811c1.js"><link rel="prefetch" href="/blog/assets/js/30.6daf7445.js"><link rel="prefetch" href="/blog/assets/js/31.a2aab18e.js"><link rel="prefetch" href="/blog/assets/js/32.e1bb66d4.js"><link rel="prefetch" href="/blog/assets/js/33.53b2c8e5.js"><link rel="prefetch" href="/blog/assets/js/34.20d63ca4.js"><link rel="prefetch" href="/blog/assets/js/35.f06bac5f.js"><link rel="prefetch" href="/blog/assets/js/36.620f1a31.js"><link rel="prefetch" href="/blog/assets/js/37.88e5acfc.js"><link rel="prefetch" href="/blog/assets/js/38.f8c44d81.js"><link rel="prefetch" href="/blog/assets/js/39.bff4d281.js"><link rel="prefetch" href="/blog/assets/js/40.3d371cdd.js"><link rel="prefetch" href="/blog/assets/js/41.4b538139.js"><link rel="prefetch" href="/blog/assets/js/5.80fcdcaf.js"><link rel="prefetch" href="/blog/assets/js/6.e7d0e536.js"><link rel="prefetch" href="/blog/assets/js/7.de89b9df.js"><link rel="prefetch" href="/blog/assets/js/8.4d1ad321.js"><link rel="prefetch" href="/blog/assets/js/9.e842551c.js">
    <link rel="stylesheet" href="/blog/assets/css/0.styles.bbb0eee4.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container have-rightmenu" data-v-f848d4e8><div class="global-loading-wrapper" data-v-137da995 data-v-f848d4e8 data-v-f848d4e8><div class="loader-main" data-v-137da995><img src="/blog/assets/img/loading.18d75e19.gif" alt="loading" data-v-137da995></div></div> <div class="hide" data-v-f848d4e8><header class="navbar" data-v-f848d4e8><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/blog/" class="home-link router-link-active"><span class="site-name">辉辉的学习基地</span></a> <div class="links"><div class="color-picker"><a class="color-button"><i class="iconfont reco-color"></i></a> <div class="color-picker-menu" style="display:none;"><div class="mode-options"><h4 class="title">选择模式</h4> <ul class="color-mode-options"><li class="dark">深色模式</li><li class="light active">浅色模式</li><li class="read">阅读模式</li></ul></div></div></div> <div class="search-box"><i class="iconfont reco-search"></i> <input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <ul class="suggestions" style="display:none;"></ul></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/blog/" class="nav-link"><i class="iconfont reco-home"></i>首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i></i>后端
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>文档教程</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-blog"></i>资源导航
</a></li><li class="dropdown-subitem"><a href="/blog/docs/spring/" class="nav-link"><i class="iconfont reco-blog"></i>Spring官网
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-api"></i>索引
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/categories/" class="nav-link"><i class="iconfont reco-category"></i>分类
</a></li><li class="dropdown-item"><!----> <a href="/blog/tags/" class="nav-link"><i class="iconfont reco-tag"></i>标签
</a></li><li class="dropdown-item"><!----> <a href="/blog/archives/" class="nav-link"><i class="iconfont reco-date"></i>归档
</a></li></ul></div></div><div class="nav-item"><a href="/blog/bookshop/message-board/" class="nav-link"><i class="iconfont reco-suggestion"></i>留言板
</a></div><div class="nav-item"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-api"></i>资源导航
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-message"></i>关于
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>联系</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-github"></i>GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="/blog/bookshop/linkme/" class="nav-link"><i class="iconfont reco-account"></i>关于我
</a></li></ul></li><li class="dropdown-item"><h4>博客</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang/blog" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-document"></i>本站源码
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li><li class="dropdown-item"><h4>其他</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/bookshop/friendslink/" class="nav-link"><i class="iconfont reco-friend"></i>友情链接
</a></li></ul></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask" data-v-f848d4e8></div> <aside class="sidebar" data-v-f848d4e8><div class="personal-info-wrapper" data-v-2cb066a4 data-v-f848d4e8><img src="/blog/img/logo.png" alt="author-avatar" class="personal-img" data-v-2cb066a4> <div class="author" data-v-2cb066a4>
    辉辉
  </div> <div class="personal-info-details" data-v-2cb066a4><div data-v-2cb066a4>文章：<span data-v-2cb066a4>19</span></div> <div data-v-2cb066a4>地点：<span data-v-2cb066a4>广东·广州</span></div></div> <div class="slogan" data-v-2cb066a4>
    Just do it
  </div> <ul class="social-links" data-v-2cb066a4><li class="social-item" data-v-2cb066a4><i class="iconfont reco-github" style="color:#24292e;" data-v-2cb066a4></i></li><li class="social-item" data-v-2cb066a4><i class="iconfont reco-csdn" style="color:#ff4d4d;" data-v-2cb066a4></i></li></ul></div> <nav class="nav-links"><div class="nav-item"><a href="/blog/" class="nav-link"><i class="iconfont reco-home"></i>首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i></i>后端
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>文档教程</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-blog"></i>资源导航
</a></li><li class="dropdown-subitem"><a href="/blog/docs/spring/" class="nav-link"><i class="iconfont reco-blog"></i>Spring官网
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-api"></i>索引
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/categories/" class="nav-link"><i class="iconfont reco-category"></i>分类
</a></li><li class="dropdown-item"><!----> <a href="/blog/tags/" class="nav-link"><i class="iconfont reco-tag"></i>标签
</a></li><li class="dropdown-item"><!----> <a href="/blog/archives/" class="nav-link"><i class="iconfont reco-date"></i>归档
</a></li></ul></div></div><div class="nav-item"><a href="/blog/bookshop/message-board/" class="nav-link"><i class="iconfont reco-suggestion"></i>留言板
</a></div><div class="nav-item"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-api"></i>资源导航
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-message"></i>关于
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>联系</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-github"></i>GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="/blog/bookshop/linkme/" class="nav-link"><i class="iconfont reco-account"></i>关于我
</a></li></ul></li><li class="dropdown-item"><h4>博客</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang/blog" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-document"></i>本站源码
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li><li class="dropdown-item"><h4>其他</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/bookshop/friendslink/" class="nav-link"><i class="iconfont reco-friend"></i>友情链接
</a></li></ul></li></ul></div></div> <!----></nav> <ul class="sidebar-links"><li><a href="/blog/pages/2765072ff5c1f/" aria-current="page" class="active sidebar-link">JVM学习</a></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper bg-style-8"><div class="articleInfo-wrap" data-v-13f19dad><div class="articleInfo" data-v-13f19dad><ul class="breadcrumbs" data-v-13f19dad><li data-v-13f19dad><a href="/blog/" title="首页" class="fa fa-laptop-house router-link-active" data-v-13f19dad></a></li> <li data-v-13f19dad><a href="/blog/categories/?category=JVM" title="分类" data-v-13f19dad>JVM</a></li> <!----> <!----></ul> <div class="info" data-v-13f19dad><div title="作者" class="author fa fa-user" data-v-13f19dad><a href="javascript:;" data-v-13f19dad>辉辉</a></div> <div title="创建时间" class="date fa fa-calendar-alt" data-v-13f19dad><a href="javascript:;" data-v-13f19dad>2021/08/19 16:46:38</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-content"></div></div></div> <h1><img src="">
            JVM学习
          </h1> <div class="theme-vdoing-content content__default"><h2 id="_1-内存结构"><a href="#_1-内存结构" class="header-anchor">#</a> 1. 内存结构</h2> <p>JVM 内存结构分为以下五大部分：</p> <ol><li>程序计数器</li> <li>虚拟机栈</li> <li>本地方法栈</li> <li>堆</li> <li>方法区</li></ol> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210812101414289.png" alt="image-20210812101414289"></p> <h3 id="_1-1-程序计数器"><a href="#_1-1-程序计数器" class="header-anchor">#</a> 1.1 程序计数器</h3> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820140731335.png" alt="image-20210820140731335"></p> <p>Program Counter Register 程序计数器（寄存器PC）</p> <ul><li>作用：记住下一条 JVM 指令的执行地址</li> <li>特点
<ul><li>是线程私有的</li> <li>不会存在内存溢出</li></ul></li></ul> <p>JVM 将 Java 源代码翻译成字节码，程序需要知道自己要执行的下一条指令的地址，这个步骤交给程序计数器来完成</p> <h3 id="_1-2-虚拟机栈"><a href="#_1-2-虚拟机栈" class="header-anchor">#</a> 1.2 虚拟机栈</h3> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820140716832.png" alt="image-20210820140716832"></p> <p>Java Virtual Machine Stacks （Java 虚拟机栈）</p> <ul><li>定义：线程运行时需要的内存空间</li> <li>特点：
<ul><li>一个程序由多个栈组成，每个栈由多个栈帧组成（一个栈帧表示一个方法的调用），每个栈帧包含：返回值、参数、局部变量、返回地址</li> <li>每个线程只能有一个活动栈帧，对应着当前正在执行的那个方法</li></ul></li></ul> <h4 id="问题辨析"><a href="#问题辨析" class="header-anchor">#</a> 问题辨析</h4> <ol><li><p><strong>垃圾回收是否涉及栈内存？</strong></p> <p>不涉及。因为栈帧内存无非就是一次次的方法调用，而栈帧内存在每次方法调用结束后就会被弹出栈，也就是会被自动回收掉，所以根本涉及不到垃圾回收，垃圾回收只是回收堆内存的无效项</p></li> <li><p><strong>栈内存的分配越大越好吗？</strong></p> <p>不是。栈内存分配得越大，反而会让线程数变少。因为我们的物理内存是固定的，一个栈的内存越大，线程数可容纳数量会变小。栈内存分配大一些，可以让方法的递归调用次数更多一些</p></li> <li><p><strong>方法内的局部变量是否线程安全？</strong></p> <ul><li>如果是线程共享的需要考虑线程安全，如果是线程私有的不需要考虑线程安全</li> <li>如果方法内局部变量没有逃离方法的作用访问，它是线程安全的</li> <li>如果是局部变量引用了对象，并逃离方法的作用范围，需要考虑线程安全</li></ul></li></ol> <h4 id="栈内存溢出"><a href="#栈内存溢出" class="header-anchor">#</a> 栈内存溢出</h4> <ul><li>栈帧过多导致栈内存溢出（递归）</li> <li>栈帧过大导致栈内存溢出</li></ul> <p>java.lang.StackOverflowError</p> <h3 id="_1-3-本地方法栈"><a href="#_1-3-本地方法栈" class="header-anchor">#</a> 1.3 本地方法栈</h3> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820140703279.png" alt="image-20210820140703279"></p> <p>Native Method Stack（本地方法栈）</p> <p>和虚拟机栈类似，是用来存储方法数据的，但它存储的是非 Java 实现的一些方法，通常这些方法都会包含 native 关键字</p> <p><strong>常见的 native 方法</strong></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">Thread</span>类
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">native</span> <span class="token class-name">Thread</span> <span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token keyword">yield</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token keyword">long</span> millis<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">start0</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">native</span> <span class="token keyword">boolean</span> <span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> <span class="token class-name">ClearInterrupted</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">boolean</span> <span class="token function">isAlive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">stop0</span><span class="token punctuation">(</span><span class="token class-name">Object</span> o<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">interrupt0</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Object</span>类
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">native</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">protected</span> <span class="token keyword">native</span> <span class="token class-name">Object</span> <span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">CloneNotSupportedException</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">notifyAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token keyword">long</span> timeout<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><h3 id="_1-4-堆"><a href="#_1-4-堆" class="header-anchor">#</a> 1.4 堆</h3> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820140654575.png" alt="image-20210820140654575"></p> <h4 id="_1-4-1-定义"><a href="#_1-4-1-定义" class="header-anchor">#</a> 1.4.1 定义</h4> <p>Heap 堆</p> <ul><li>通过 new 关键字，创建对象都会存放在堆内存</li></ul> <p>特点</p> <ul><li>线程共享，堆中对象都需要考虑线程安全的问题</li> <li>有垃圾回收机制</li></ul> <h4 id="_1-4-2-堆内存溢出"><a href="#_1-4-2-堆内存溢出" class="header-anchor">#</a> 1.4.2 堆内存溢出</h4> <p>java.lang.OutOfMemoryError: Java heap space</p> <h4 id="_1-4-3-堆内存诊断"><a href="#_1-4-3-堆内存诊断" class="header-anchor">#</a> 1.4.3 堆内存诊断</h4> <ol><li>jps 工具
查看当前系统中有哪些 java 进程</li> <li>jmap 工具
查看堆内存占用情况 jmap - heap 进程id</li> <li>jconsole 工具
图形界面的，多功能的监测工具，可以连续监测</li></ol> <p>案例</p> <ul><li>垃圾回收后，内存占用仍然很高</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ArrayList</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HeapErrorTest</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">String</span> a <span class="token operator">=</span> <span class="token string">&quot;hello&quot;</span><span class="token punctuation">;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
                a <span class="token operator">=</span> a <span class="token operator">+</span> a<span class="token punctuation">;</span>
                i<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210819160118374.png" alt="image-20210819160118374"></p> <h3 id="_1-5-方法区"><a href="#_1-5-方法区" class="header-anchor">#</a> 1.5 方法区</h3> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820120201249.png" alt="image-20210820120201249"></p> <h4 id="_1-5-1-定义"><a href="#_1-5-1-定义" class="header-anchor">#</a> 1.5.1 定义</h4> <ul><li>方法区（Method Area）与 Java 堆一样，是所有线程共享的内存区域。</li> <li>JDK7 之前（永久代）用于存储已被虚拟机加载的类信息、常量、字符串常量、类静态变量、即时编译器编译后的代码等数据。</li> <li>Java 虚拟机规范把方法区描述为堆的一个逻辑部分，但是它却有一个别名叫做 Non-Heap（非堆），目的应该是与 Java 堆区分开来。</li> <li>运行时常量池（Runtime Constant Pool）是方法区的一部分。Class 文件中除了有类的版本/字段/方法/接口等描述信息外，还有一项信息是常量池（Constant Pool Table），用于存放编译期生成的各种字面量和符号引用，这部分内容将类在加载后进入方法区的运行时常量池中存放。运行期间也可能将新的常量放入池中，这种特性被开发人员利用得比较多的是 String.intern() 方法。受方法区内存的限制，当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。</li></ul> <p>随着 JDK 版本迁移的方法区</p> <p>JDK6</p> <ul><li>Class 元数据信息</li> <li>每个类的运行时常量池（字段、方法、类、接口等符号引用）、编译后的代码</li> <li>静态字段（无论是否有final）在 instanceKlass 末尾（位于 PermGen 内）</li> <li>oop（Ordinary Object Pointer（普通对象指针）） 其实就是 Class 对象实例</li> <li>全局字符串常量池 StringTable，本质上就是个 Hashtable</li> <li>符号引用（类型指针是 SymbolKlass）</li></ul> <p>JDK7</p> <ul><li>Class 元数据信息</li> <li>每个类的运行时常量池（字段、方法、类、接口等符号引用）、编译后的代码</li> <li>静态字段从 instanceKlass 末尾移动到了 java.lang.Class 对象（oop）的末尾（位于 Java Heap 内）</li> <li>oop 与全局字符串常量池移到 Java Heap 上</li> <li>符号引用被移动到 Native Heap 中</li></ul> <p>JDK8</p> <ul><li>移除永久代</li> <li>Class 元数据信息</li> <li>每个类的运行时常量池、编译后的代码移到了另一块与堆不相连的本地内存 -- 元空间（Metaspace）</li></ul> <h4 id="_1-5-2-组成"><a href="#_1-5-2-组成" class="header-anchor">#</a> 1.5.2 组成</h4> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820120123932.png" alt="image-20210820120123932"></p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820120149097.png" alt="image-20210820120149097"></p> <h4 id="_1-5-3-方法区内存溢出"><a href="#_1-5-3-方法区内存溢出" class="header-anchor">#</a> 1.5.3 方法区内存溢出</h4> <ul><li>1.8 以前会导致永久代内存溢出</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>永久代内存溢出 java.lang.OutOfMemoryError: PermGen space
-XX:MaxPermSize=8m
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><ul><li>1.8 之后会导致元空间内存溢出</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>演示元空间内存溢出 java.lang.OutOfMemoryError: Metaspace
-XX:MaxMetaspaceSize=8m
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="_1-5-4-运行时常量池"><a href="#_1-5-4-运行时常量池" class="header-anchor">#</a> 1.5.4 运行时常量池</h4> <ul><li>常量池，就是一张表，虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息</li> <li>运行时常量池，常量池是 *.class 文件中的，当该类被加载，它的常量池信息就会放入运行时常量池，并把里面的符号地址变为真实地址</li></ul> <h4 id="_1-5-5-stringtable"><a href="#_1-5-5-stringtable" class="header-anchor">#</a> 1.5.5 StringTable</h4> <p>先看几道面试题：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">String</span> s1 <span class="token operator">=</span> <span class="token string">&quot;a&quot;</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> s2 <span class="token operator">=</span> <span class="token string">&quot;b&quot;</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> s3 <span class="token operator">=</span> <span class="token string">&quot;a&quot;</span> <span class="token operator">+</span> <span class="token string">&quot;b&quot;</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> s4 <span class="token operator">=</span> s1 <span class="token operator">+</span> s2<span class="token punctuation">;</span>
<span class="token class-name">String</span> s5 <span class="token operator">=</span> <span class="token string">&quot;ab&quot;</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> s6 <span class="token operator">=</span> s4<span class="token punctuation">.</span><span class="token function">intern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 问</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>s3 <span class="token operator">==</span> s4<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>s3 <span class="token operator">==</span> s5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>s3 <span class="token operator">==</span> s6<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> x2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">&quot;c&quot;</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">&quot;d&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> x1 <span class="token operator">=</span> <span class="token string">&quot;cd&quot;</span><span class="token punctuation">;</span>
x2<span class="token punctuation">.</span><span class="token function">intern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 问，如果调换了【最后两行代码】的位置呢，如果是jdk1.6呢</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>x1 <span class="token operator">==</span> x2<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><h4 id="_1-5-6-stringtable-特性"><a href="#_1-5-6-stringtable-特性" class="header-anchor">#</a> 1.5.6 StringTable 特性</h4> <ul><li>常量池中的字符串仅是符号，第一次用到时才变为对象</li> <li>利用串池的机制，来避免重复创建字符串对象</li> <li>字符串变量拼接的原理是 StringBuilder （1.8）</li> <li>字符串常量拼接的原理是编译期优化</li> <li>可以使用 intern 方法，主动将串池中还没有的字符串对象放入串池
<ul><li>1.8 将这个字符串对象尝试放入串池，如果有则并不会放入，如果没有则放入串池， 会把串池中的对象返回</li> <li>1.6 将这个字符串对象尝试放入串池，如果有则并不会放入，如果没有会把此对象复制一份，放入串池， 会把串池中的对象返回</li></ul></li></ul> <h4 id="_1-5-7-stringtable-位置"><a href="#_1-5-7-stringtable-位置" class="header-anchor">#</a> 1.5.7 StringTable 位置</h4> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820120123932.png" alt="image-20210820120123932"></p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820120149097.png" alt="image-20210820120149097"></p> <p>在 JDK 1.6的时候，是常量池的一部分，与常量池存在永久代中；在 JDK 1.7、1.8中，将 StringTable 转移到了堆中</p> <p>更改原因：永久代的回收效率很低，永久代需要在 full gc 的时候才会触发 gc 操作，而字符串操作在 Java 中是比较常用的，会产生大量的垃圾，所以 JDK 1.7、1.8 将 StringTable 转移到了堆中，堆中的是 minor gc</p> <h4 id="_1-5-8-stringtable-垃圾回收"><a href="#_1-5-8-stringtable-垃圾回收" class="header-anchor">#</a> 1.5.8  StringTable 垃圾回收</h4> <p>加上下面参数可以查看 StringTable 在 JVM 中 垃圾回收时的日志</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>-XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>一开始啥也不干</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StringTableTest</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820151109741.png" alt="image-20210820151109741"></p> <p>给串池中加入100个字符串</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StringTableTest</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">100</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>j<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">intern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                i<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820151451591.png" alt="image-20210820151451591"></p> <p>可以发现存储键值对的个数和串池中字符串的个数耶都增加了100个</p> <p><strong>查看串池中被 gc 回收的现象</strong></p> <p>没被回收前，初始日志信息状态：</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820152215474.png" alt="image-20210820152215474"></p> <p>限制 JVM 最大内存的大小</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>-Xmx10m
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>然后循环 10000 次</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820152925478.png" alt="image-20210820152925478"></p> <h4 id="_1-5-9-stringtable-性能调优"><a href="#_1-5-9-stringtable-性能调优" class="header-anchor">#</a> 1.5.9 StringTable 性能调优</h4> <p>可以知道 StringTable 是基于类似 hash 桶的个数这种方式进行存储的，桶的个数越多，分散的位置就越多，所以查询就越快，反之就越慢，所以 StringTable 的调优调的就是 StringTable 桶的个数</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>-XX:StringTableSize=20000
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h3 id="_1-6-直接内存"><a href="#_1-6-直接内存" class="header-anchor">#</a> 1.6 直接内存</h3> <h4 id="_1-6-1-定义"><a href="#_1-6-1-定义" class="header-anchor">#</a> 1.6.1 定义</h4> <p>Direct Memory</p> <ul><li>是操作系统的内存</li> <li>常见于 NIO 操作时，用于数据缓冲区</li> <li>分配回收成本较高，但读写性能高</li> <li>不受 JVM 内存回收管理</li></ul> <h4 id="_1-6-2-分配和回收原理"><a href="#_1-6-2-分配和回收原理" class="header-anchor">#</a> 1.6.2 分配和回收原理</h4> <ul><li>使用了 Unsafe 对象完成直接内存的分配回收，并且回收需要主动调用 freeMemory 方法</li> <li>ByteBuffer 的实现类内部，使用了 Cleaner （虚引用）来监测 ByteBuffer 对象，一旦ByteBuffer 对象被垃圾回收，那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存</li></ul> <h4 id="_1-6-3-bytebuffer-与普通-io-的性能对比"><a href="#_1-6-3-bytebuffer-与普通-io-的性能对比" class="header-anchor">#</a> 1.6.3 ByteBuffer 与普通 IO 的性能对比</h4> <p>ByteBuffer 使用的是直接内存去操作 IO</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">FileInputStream</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">FileOutputStream</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">IOException</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span></span><span class="token class-name">ByteBuffer</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span>channels<span class="token punctuation">.</span></span><span class="token class-name">FileChannel</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DirectMemoryTest</span> <span class="token punctuation">{</span>
    <span class="token comment">// 视频大概100多m</span>
    <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> FROM <span class="token operator">=</span> <span class="token string">&quot;D:\\Downloads\\01springboot\\视频\\1.传统SSM开发回顾以及问题.mp4&quot;</span><span class="token punctuation">;</span>
    <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> TO <span class="token operator">=</span> <span class="token string">&quot;D:\\a.mp4&quot;</span><span class="token punctuation">;</span>
    <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> _1MB <span class="token operator">=</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">io</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">directBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">directBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">(</span>
                <span class="token class-name">FileChannel</span> from <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span>FROM<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getChannel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">FileChannel</span> <span class="token keyword">to</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileOutputStream</span><span class="token punctuation">(</span>TO<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getChannel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">ByteBuffer</span> bb <span class="token operator">=</span> <span class="token class-name">ByteBuffer</span><span class="token punctuation">.</span><span class="token function">allocateDirect</span><span class="token punctuation">(</span>_1MB<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">int</span> len <span class="token operator">=</span> from<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span>bb<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>len <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">break</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
                bb<span class="token punctuation">.</span><span class="token function">flip</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">to</span><span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>bb<span class="token punctuation">)</span><span class="token punctuation">;</span>
                bb<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;bytebuffer 用时：&quot;</span> <span class="token operator">+</span> <span class="token punctuation">(</span>end <span class="token operator">-</span> start<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">1000_000.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">io</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">(</span>
                <span class="token class-name">FileInputStream</span> from <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span>FROM<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">FileOutputStream</span> <span class="token keyword">to</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileOutputStream</span><span class="token punctuation">(</span>TO<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">final</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> buf <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span>_1MB<span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">int</span> len <span class="token operator">=</span> from<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>len <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">break</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
                <span class="token keyword">to</span><span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>buf<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;io 用时：&quot;</span> <span class="token operator">+</span> <span class="token punctuation">(</span>end <span class="token operator">-</span> start<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">1000_000.0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br></div></div><p>执行结过</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820160102731.png" alt="image-20210820160102731"></p> <p>可以得出 ByteBuffer 操作直接内存比 Java 操作 IO 快得多</p> <h4 id="_1-6-4-磁盘读写过程分析"><a href="#_1-6-4-磁盘读写过程分析" class="header-anchor">#</a> 1.6.4 磁盘读写过程分析</h4> <p>Java 读取磁盘文件过程</p> <p>Java 本身是不具备磁盘读写能力的，它是通过调用 Java 方法去调用本地方法（用户态切换到内核态）</p> <p>Java 将磁盘文件读入到系统缓冲区，系统缓冲区 Java 是没办法读取的，所以在堆内存中分配一块 Java 缓冲区，然后将数据从系统缓冲区读入到 Java 缓冲区，最后切换下一个状态（用户态 → 内核态 → 用户态）</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820162305834.png" alt="image-20210820162305834"></p> <hr> <p>ByteBuffer 读取磁盘文件过程</p> <p>ByteBuffer 会在 Java 堆内存和系统堆内存直接建立直接内存区域，这块区域 Java 和操作系统都能够访问，所以就减少了访问磁盘文件的时间</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820163117743.png" alt="image-20210820163117743"></p> <h4 id="_1-6-5-内存溢出"><a href="#_1-6-5-内存溢出" class="header-anchor">#</a> 1.6.5 内存溢出</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span></span><span class="token class-name">ByteBuffer</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ArrayList</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DirectMemoryTest2</span> <span class="token punctuation">{</span>
    <span class="token keyword">static</span> <span class="token keyword">int</span> _100MB <span class="token operator">=</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ByteBuffer</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">ByteBuffer</span> bb <span class="token operator">=</span> <span class="token class-name">ByteBuffer</span><span class="token punctuation">.</span><span class="token function">allocateDirect</span><span class="token punctuation">(</span>_100MB<span class="token punctuation">)</span><span class="token punctuation">;</span>
                list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>bb<span class="token punctuation">)</span><span class="token punctuation">;</span>
                i<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820163936367.png" alt="image-20210820163936367"></p> <h4 id="_1-6-6-bytebuffer-回收垃圾原理"><a href="#_1-6-6-bytebuffer-回收垃圾原理" class="header-anchor">#</a> 1.6.6 ByteBuffer 回收垃圾原理</h4> <ul><li>使用了 Unsafe 对象完成直接内存的分配回收，并且回收需要主动调用 freeMemory 方法</li> <li>ByteBuffer 的实现类内部，使用了Cleaner（虚引用）来监测 ByteBuffer 对象，一旦 ByteBuffer 对象被垃圾回收，那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存</li></ul> <hr> <h2 id="_2-垃圾回收"><a href="#_2-垃圾回收" class="header-anchor">#</a> 2. 垃圾回收</h2> <ol><li>如何判断对象可以回收</li> <li>垃圾回收算法</li> <li>分代垃圾回收</li> <li>垃圾回收器</li> <li>垃圾回收调优</li></ol> <h3 id="_2-1-如何判断对象可以回收"><a href="#_2-1-如何判断对象可以回收" class="header-anchor">#</a> 2.1 如何判断对象可以回收</h3> <h4 id="_2-1-1-引用计数法"><a href="#_2-1-1-引用计数法" class="header-anchor">#</a> 2.1.1 引用计数法</h4> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210820165355637.png" alt="image-20210820165355637"></p> <ul><li>原理：通过在对象头中分配一个空间来保存该对象被引用的次数。如果该对象被其它对象引用，则它的引用计数加一，如果删除对该对象的引用，那么它的引用计数就减一，当该对象的引用计数为0时，那么该对象就会被回收</li> <li>问题：
<ul><li>无法处理循环引用的情况</li> <li>堆内对象的每一次引用赋值和每一次引用清除，都伴随着加减法的操作，会带来一定的性能开销</li></ul></li></ul> <h4 id="_2-1-2-可达性分析算法"><a href="#_2-1-2-可达性分析算法" class="header-anchor">#</a> 2.1.2 可达性分析算法</h4> <ul><li>Java 虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象</li> <li>扫描堆中的对象，看是否能够沿着 GC Root对象 为起点的引用链找到该对象，找不到，表示可以回收</li> <li>哪些对象可以作为 GC Root ?</li></ul> <h4 id="_2-1-3-四种引用"><a href="#_2-1-3-四种引用" class="header-anchor">#</a> 2.1.3 四种引用</h4> <ol><li>强引用
只有所有 GC Roots 对象都不通过【强引用】引用该对象，该对象才能被垃圾回收</li> <li>软引用（SoftReference）
仅有软引用引用该对象时，在垃圾回收后，内存仍不足时会再次出发垃圾回收，回收软引用对象
可以配合引用队列来释放软引用自身</li> <li>弱引用（WeakReference）
仅有弱引用引用该对象时，在垃圾回收时，无论内存是否充足，都会回收弱引用对象
可以配合引用队列来释放弱引用自身</li> <li>虚引用（PhantomReference）
必须配合引用队列使用，主要配合 ByteBuffer 使用，被引用对象回收时，会将虚引用入队，由 Reference Handler 线程调用虚引用相关方法释放直接内存</li> <li>终结器引用（FinalReference）
无需手动编码，但其内部配合引用队列使用，在垃圾回收时，终结器引用入队（被引用对象暂时没有被回收），再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize 方法，第二次 GC 时才能回收被引用对象</li></ol> <p><strong>软引用的使用</strong></p> <p>比如说存储图片资源，我们可能会使用 byte[] 去存储，而图片资源并不算核心业务资源，使用对象存储会浪费系统空间，所以可以考虑在</p></div></div> <div class="page-edit"><div class="tags"><a href="/blog/tags/?tag=JVM%E5%AD%A6%E4%B9%A0" title="标签">#JVM学习</a></div> <div class="last-updated"><span class="prefix">最近更新时间：</span> <span class="time">2021/09/02 00:18:49</span></div></div> <div class="page-nav-wapper"><!----> <!----></div></div> <div class="theme-vdoing-wrapper article-list bg-style-3"><div class="article-title"><a href="/blog/archives/" class="fa fa-pencil-alt">
      最近更新
    </a></div> <div class="article-wrapper"><dl><dd>01</dd> <dt><div><a href="/blog/pages/6158565fa6669/"><div>数字广东公司工作总结</div></a></div> <div class="date"><span>2021/12/08 09:39:37</span></div></dt></dl><dl><dd>02</dd> <dt><div><a href="/blog/pages/ad577fcaceee3/"><div>Spring Data基础</div></a></div> <div class="date"><span>2021/11/24 16:51:26</span></div></dt></dl><dl><dd>03</dd> <dt><div><a href="/blog/pages/6976a1db349ce/"><div>如何参加github开源项目</div></a></div> <div class="date"><span>2021/11/17 18:29:14</span></div></dt></dl> <div class="more-box"><a href="/blog/archives/" class="more"><i class="fas fa-angle-double-right"></i>前往更多 ...
      </a></div></div></div> <div class="comments-wrapper" style="display:none;"><!----></div></main></div> <div class="footer-wrapper" data-v-4c8cc972 data-v-4c8cc972><span class="footer-reco-theme" data-v-4c8cc972><i class="iconfont reco-github" data-v-4c8cc972></i> <a target="blank" href="https://github.com/YanHui-Yang" data-v-4c8cc972>HuiBlog@1.0</a></span> <!----> <span class="footer-copyright" data-v-4c8cc972><i class="iconfont reco-copyright" data-v-4c8cc972></i> <a data-v-4c8cc972><span data-v-4c8cc972>辉辉</span> <span class="ml5" data-v-4c8cc972>
          2021 - 至今
        </span></a></span> <span class="footer-view-site" data-v-4c8cc972><i class="iconfont reco-eye" data-v-4c8cc972></i> <span id="busuanzi_container_site_uv" data-v-4c8cc972>
        访客数：<span id="busuanzi_value_site_uv" class="num" data-v-4c8cc972>-</span></span> <span id="busuanzi_container_site_pv" class="ml5" data-v-4c8cc972>
        访问量：<span id="busuanzi_value_site_pv" class="num" data-v-4c8cc972>-</span></span></span> <!----></div></div></div><div class="global-ui"><div class="back-to-ceiling" style="right:1rem;bottom:6rem;width:2.5rem;height:2.5rem;border-radius:.25rem;line-height:2.5rem;display:none;" data-v-c6073ba8 data-v-c6073ba8><svg t="1574745035067" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" class="icon" data-v-c6073ba8><path d="M526.60727968 10.90185116a27.675 27.675 0 0 0-29.21455937 0c-131.36607665 82.28402758-218.69155461 228.01873535-218.69155402 394.07834331a462.20625001 462.20625001 0 0 0 5.36959153 69.94390903c1.00431239 6.55289093-0.34802892 13.13561351-3.76865779 18.80351572-32.63518765 54.11355614-51.75690182 118.55860487-51.7569018 187.94566865a371.06718723 371.06718723 0 0 0 11.50484808 91.98906777c6.53300375 25.50556257 41.68394495 28.14064038 52.69160883 4.22606766 17.37162448-37.73630017 42.14135425-72.50938081 72.80769204-103.21549295 2.18761121 3.04276886 4.15646224 6.24463696 6.40373557 9.22774369a1871.4375 1871.4375 0 0 0 140.04691725 5.34970492 1866.36093723 1866.36093723 0 0 0 140.04691723-5.34970492c2.24727335-2.98310674 4.21612437-6.18497483 6.3937923-9.2178004 30.66633723 30.70611158 55.4360664 65.4791928 72.80769147 103.21549355 11.00766384 23.91457269 46.15860503 21.27949489 52.69160879-4.22606768a371.15156223 371.15156223 0 0 0 11.514792-91.99901164c0-69.36717486-19.13165746-133.82216804-51.75690182-187.92578088-3.42062944-5.66790279-4.76302748-12.26056868-3.76865837-18.80351632a462.20625001 462.20625001 0 0 0 5.36959269-69.943909c-0.00994388-166.08943902-87.32547796-311.81420293-218.6915546-394.09823051zM605.93803103 357.87693858a93.93749974 93.93749974 0 1 1-187.89594924 6.1e-7 93.93749974 93.93749974 0 0 1 187.89594924-6.1e-7z" p-id="5405" data-v-c6073ba8></path><path d="M429.50777625 765.63860547C429.50777625 803.39355007 466.44236686 1000.39046097 512.00932183 1000.39046097c45.56695499 0 82.4922232-197.00623328 82.5015456-234.7518555 0-37.75494459-36.9345906-68.35043303-82.4922232-68.34111062-45.57627738-0.00932239-82.52019037 30.59548842-82.51086798 68.34111062z" p-id="5406" data-v-c6073ba8></path></svg></div><!----><div></div></div></div>
    <script src="/blog/assets/js/app.4c41a59b.js" defer></script><script src="/blog/assets/js/2.a039f8e7.js" defer></script><script src="/blog/assets/js/23.da1cba87.js" defer></script><script src="/blog/assets/js/4.bae9b8d2.js" defer></script>
  </body>
</html>
